package org.papervision3d.core.geom
{
	import flash.display.DisplayObjectContainer;
	import org.papervision3d.core.proto.DisplayObjectContainer3D;
	import org.papervision3d.core.Matrix3D;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.core.Number3D;
	
	public class Spline3D extends Vertices3D
	{
		
		/**
		 * @return valeur Boolean indiquant si la spline est fermé (true) ou non
		 * 
		 */		
		public function get closed() : Boolean {
			return _closed;
		}
		
		
		function Spline3D(name:String = null, initObject:Object = null)
        {
            super(name, initObject);
        }
        
        public function transposeToParent() : void {
//        	var m:Matrix3D = DisplayObject3D( parent ).transform;
        	var m:Matrix3D = transform;//Matrix3D.inverse( transform );
    		
    		//trace( "localeToParentTransform  : "+parent );
           	for each( var v : Vertex3D in vertices ) {

	            var vx:Number = v.x;
	            var vy:Number = v.y;
	            var vz:Number = v.z;
	
	            var sx:Number = vx * m.n11 + vy * m.n12 + vz * m.n13 + m.n14;
	            var sy:Number = vx * m.n21 + vy * m.n22 + vz * m.n23 + m.n24;
	            var sz:Number = vx * m.n31 + vy * m.n32 + vz * m.n33 + m.n34;
	
				v.x = sx;
				v.y = sy;
				v.z = sz;
           	}
    		//trace("  		", v.x, v.y, v.z );
		}
		
		/**
		 * renvoi un point sur la spline 
		 * @param progress
		 * @return 
		 * 
		 */		
		public function getPosition( progress : Number ) : Number3D {
			
			var x : Number = getDirPosition( "x", progress );
			var y : Number = getDirPosition( "y", progress );
			var z : Number = getDirPosition( "z", progress );
			return new Number3D( x,y,z );
		}
		
		/**
		 * renvoi la derivé d'un point 
		 * @param progress
		 * @return 
		 * 
		 */		
		public function getDirection( progress : Number ) : Number3D {
			
			if( progress > 0.89 ) progress = 0.89
			var d0 : Number3D = getPosition( progress );
			var d1 : Number3D = getPosition( progress + 0.1 );
			
			var dv : Number3D = Number3D.sub( d1, d0 );
			dv.normalize();
			return dv;
		}
		
		
        
        
        //__________________________________________________________________
        //															PRIVATES
        
        private function getDirPosition( prop : String, t : Number ) : Number {
        	t = Math.max( 0.001, Math.min( 0.999, t ));
        	var p : Array = new Array();
        	for( var n : int = 1; n < vertices.length - 1; n++ ) p.push( vertices[n][prop] ); 
        	var b : Number = vertices[0][prop];
        	var e : Number = vertices[vertices.length- 1 ][prop];
        	
			if (p.length == 1) {
				// Simple curve with just one bezier control point
				return b + t*(2*(1-t)*(p[0]-b) + t*(e - b));
			} else {
				// Array of bezier control points, must find the point between each pair of bezier points
				var ip:uint = Math.floor(t * p.length); // Position on the bezier list
				var it:Number = (t - (ip * (1 / p.length))) * p.length; // t inside this ip
				var p1:Number, p2:Number;
				if (ip == 0) {
					// First part: belongs to the first control point, find second midpoint
					p1 = b;
					p2 = (p[0]+p[1])/2;
				} else if (ip == p.length - 1) {
					// Last part: belongs to the last control point, find first midpoint
					p1 = (p[ip-1]+p[ip])/2;
					p2 = e;
				} else {
					// Any middle part: find both midpoints
					p1 = (p[ip-1]+p[ip])/2;
					p2 = (p[ip]+p[ip+1])/2;
				}
				return p1+it*(2*(1-it)*(p[ip]-p1) + it*(p2 - p1));
			}
        }
        
        
        /**
        * spline fermé ou non
        */        
        private var _closed : Boolean;
	}
}